/*
 file: utils.js
 dependsOn: core.js
 */

/*--------------------------- Date extensions -------------------------------*/

/**
 * When invoked, returns the current timestamp (just like new Date().getTime())
 * @return The current timestamp (ms since epoch)
 */
Date.now = Date.now || function() {
  return new Date().getTime();
};

/*-------------------------- RegExp extensions ------------------------------*/

/**
 * Returns a copy of the passed String with all characters that have
 * special meaning in a regular expression escaped.
 * @param {String} string The string to escape
 * @return {String} The escaped string
 */
RegExp.escape = function(string) {
  return String(string).replace($._R.RExSC, '\\$1');
};


/*--------------------------- Extensions to $ -------------------------------*/

$.extend($, 
{  
  /**
   * Cancels the specified timer (whether an interval or timeout),
   * such that it will never fire again (or ever, if it has yet to).
   * @param {Object} timer The timer to cancel
   */
  cancel: function(timer)
  {    
  	clearTimeout(timer);
  	clearInterval(timer);
  },
  
  inspect: function(object) 
  {
    return object == null ? 
      object === null ? 'null' : 'undefined' : 
      object.inspect ? object.inspect() : String(object);
  },
  
  /**
   * Tests whether the passed object is an Array
   * @alias $.isArray
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is an Array, false otherwise
   * @since 0.1
   */
  isArray: function(object) 
  {
    return object && object.constructor === Array;
  },

  /**
   * Tests whether the passed object is defined (not null or undefined)
   * @alias $.isDefined
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is defined, false otherwise
   * @since 0.1
   */
  isDefined: function(object) 
  {
    return object != null;
  },

  /**
   * Tests whether the passed object is an Function
   * @alias $.isFunction
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is an Function, false otherwise
   * @since 0.1
   */
  isFunction: function(object) 
  {
    return typeof object == 'function';
  },

  /**
   * Tests whether the passed object is an DOM node (included those 
   * wrapped in Elements)
   * @alias $.isNode
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is a DOM node or an Element, 
   *  false otherwise
   * @since 0.1
   */
  isNode: function(object) 
  {
    return object != null && object.nodeType == 1;
  },

  /**
   * Tests whether the passed object is an Number
   * @alias $.isNumber
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is an Number, false otherwise
   * @since 0.1
   */
  isNumber: function(object) 
  {
    return typeof object == 'number';
  },

  /**
   * Tests whether the passed object is an Object
   * @alias $.isObject
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is an Object, false otherwise
   * @since 0.1
   */
  isObject: function(object) 
  {
    return typeof object == 'object' && object != null;
  },

  /**
   * Tests whether the passed object is an String
   * @alias $.isString
   * @param  {Object}  object The object to test
   * @return {Boolean} True if the object is an String, false otherwise
   * @since 0.1
   */
  isString: function(object) 
  {
    return typeof object == 'string';
  },

  keys: function(object) 
  {
    var property, keys = [];
    
    for (property in object) 
      keys.push(property);
      
    return keys;
  },
  
  toHTML: function(object) 
  {
    return object == null ? '' : object.toHTML ? object.toHTML() : String(object);
  },
  
  toQueryString: function(object) {
    return $.Hash(object).toQueryString();
  },
  
  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },
  
  /*
   * Private object for storing precompiled regular expressions
   */
  _R:
  {
    // Special characters in regular expressions that need to be escaped
    RExSC: /([.*+?^=!:${}()|[\]\/\\])/g
  }  
});
